package com.netty.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netty.common.protocol.RpcRequest;
import com.netty.connect.ConnectManage;
import com.netty.future.RPCFuture;
import com.netty.handler.RpcClientHandler;

public class ObjectProxy<T> implements InvocationHandler, IAsyncObjectProxy {

	public static final Logger logger = LoggerFactory.getLogger(ObjectProxy.class);
	
	private Class<T> clazz;
	
	public ObjectProxy(Class<T> clazz){
		this.clazz = clazz;
	}
	
	/**
	 * 同步回调
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if (Object.class == method.getDeclaringClass()) {
			String name = method.getName();
			if ("equals".equals(name)) {
				return proxy == args[0];
			}else if ("hashCode".equals(name)) {
				return System.identityHashCode(proxy);
			}else if ("toString".equals(name)) {
				return proxy.getClass().getName()+"@"+
						Integer.toHexString(System.identityHashCode(proxy))+
						", with InvocationHandler"+this;
			}else {
				throw new IllegalStateException(String.valueOf(method));
			}
		}
		RpcRequest request = new RpcRequest();
		request.setRequestId(UUID.randomUUID().toString());
		request.setClassName(method.getDeclaringClass().getName());
		request.setMethodName(method.getName());
		request.setParameterTypes(method.getParameterTypes());
		request.setParameters(args);
		logger.info(method.getDeclaringClass().getName());
		logger.info(method.getName());
		for (int i = 0; i < method.getParameterTypes().length; i++) {
			logger.info(method.getParameterTypes()[i].getName());
		}
		for (int i = 0; i < args.length; i++) {
			logger.info(args[i].toString());
		}
		RpcClientHandler handler = ConnectManage.getInstance().chooseHandler();
		RPCFuture future = handler.sendRequest(request);
		return future.get();
	}

	/**
	 * 异步回调
	 */
	@Override
	public RPCFuture call(String methodName, Object... args) {
		RpcClientHandler handler = ConnectManage.getInstance().chooseHandler();
		RpcRequest request = createRequest(this.clazz.getName(), methodName,args);
		RPCFuture future = handler.sendRequest(request);
		return future;
	}

	private RpcRequest createRequest(String className, String methodName, Object[] args) {
		RpcRequest request = new RpcRequest();
		request.setRequestId(UUID.randomUUID().toString());
		request.setClassName(className);
		request.setMethodName(methodName);
		request.setParameters(args);
		Class<?>[] parameterTypes = new Class[args.length];
		for (int i = 0; i < args.length; i++) {
			parameterTypes[i] = getClassType(args[i]);
		}
		request.setParameterTypes(parameterTypes);
		logger.debug(className);
		logger.debug(methodName);
		for (int i = 0; i < parameterTypes.length; i++) {
			logger.debug(parameterTypes[i].getName());
		}
		for (int i = 0; i < args.length; i++) {
			logger.debug(args[i].toString());
		}
		return request;
	}

	private Class<?> getClassType(Object object) {
		Class<?> classType = object.getClass();
		String typeName = classType.getName();
		switch (typeName) {
        case "java.lang.Integer":
            return Integer.TYPE;
        case "java.lang.Long":
            return Long.TYPE;
        case "java.lang.Float":
            return Float.TYPE;
        case "java.lang.Double":
            return Double.TYPE;
        case "java.lang.Character":
            return Character.TYPE;
        case "java.lang.Boolean":
            return Boolean.TYPE;
        case "java.lang.Short":
            return Short.TYPE;
        case "java.lang.Byte":
            return Byte.TYPE;
    }

    return classType;
	}
	


}
